#include "elaphureLink_protocol.h" // 引入elaphureLink协议头文件
#include "dap_main.h"                               // 引入DAP句柄处理头文件
#include "lwip/err.h"                                      // 引入LWIP错误处理头文件
#include "lwip/sockets.h"                                  // 引入LWIP套接字头文件
#include "lwip/sys.h"                                      // 引入LWIP系统头文件
#include <lwip/netdb.h>                                    // 引入LWIP网络数据库头文件
#include "esp_log.h"                                      // 引入ESP日志头文件
// 外部变量声明
extern int kRestartDAPHandle;                                                      // 声明外部变量：DAP句柄重启标志
extern int kSock;                                                                  // 声明外部变量：套接字描述符
extern int usbip_network_send(int s, const void *dataptr, size_t size, int flags); // 声明外部函数：网络发送函数

// 外部函数声明
extern void malloc_dap_ringbuf();                                              // 声明外部函数：分配DAP环形缓冲区
extern void free_dap_ringbuf();                                                // 声明外部函数：释放DAP环形缓冲区
extern uint32_t DAP_ExecuteCommand(const uint8_t *request, uint8_t *response); // 声明外部函数：执行DAP命令

// elaphureLink上下文结构体
struct el_context
{
    bool is_async; // 是否异步模式标志
};

// 全局变量
static struct el_context k_el_context; // 定义全局变量：elaphureLink上下文实例
uint8_t *el_process_buffer = NULL;     // 定义全局变量：处理缓冲区指针

/**
 * @brief 分配处理缓冲区
 * 如果缓冲区已分配则直接返回，否则释放DAP环形缓冲区并分配新缓冲区
 */
void el_process_buffer_malloc()
{
    if (el_process_buffer != NULL) // 如果缓冲区已分配
        return;                    // 直接返回

    free_dap_ringbuf();               // 释放DAP环形缓冲区
    el_process_buffer = malloc(1500); // 分配1500字节缓冲区
}

/**
 * @brief 释放处理缓冲区
 * 如果缓冲区不为空，则释放它并将指针置为NULL
 */
void el_process_buffer_free()
{
    if (el_process_buffer != NULL) // 如果缓冲区不为空
    {
        free(el_process_buffer);  // 释放缓冲区
        el_process_buffer = NULL; // 指针置为NULL
    }
}

/**
 * @brief 握手处理函数
 * @param fd 套接字描述符
 * @param buffer 接收到的数据缓冲区
 * @param len 数据长度
 * @return 成功返回0，失败返回-1
 */
int el_handshake_process(int fd, void *buffer, size_t len)
{
    // 检查数据长度是否匹配
    if (len != sizeof(el_request_handshake)) // 如果长度不匹配
    {
        return -1; // 返回失败
    }

    el_request_handshake *req = (el_request_handshake *)buffer; // 转换缓冲区为握手请求结构体
    // todo 待删除前面已经判断过了
    //  检查标识符是否匹配
    if (ntohl(req->el_link_identifier) != EL_LINK_IDENTIFIER) // 如果标识符不匹配
    {
        return -1; // 返回失败
    }

    // 检查命令是否为握手
    if (ntohl(req->command) != EL_COMMAND_HANDSHAKE) // 如果命令不是握手
    {
        return -1; // 返回失败
    }

    // 准备握手响应
    el_response_handshake res;                          // 定义握手响应结构体
    res.el_link_identifier = htonl(EL_LINK_IDENTIFIER); // 设置标识符
    res.command = htonl(EL_COMMAND_HANDSHAKE);          // 设置命令为握手
    res.el_dap_version = htonl(EL_DAP_VERSION);         // 设置DAP版本

    // 发送握手响应
    usbip_network_send(fd, &res, sizeof(el_response_handshake), 0); // 发送响应

    return 0; // 返回成功
}

/**
 * @brief DAP数据处理函数
 * @param buffer 接收到的数据缓冲区
 * @param len 数据长度
 */
void el_dap_data_process(void *buffer, size_t len)
{
    // 执行DAP命令并获取结果长度
    int res = DAP_ExecuteCommand(buffer, (uint8_t *)el_process_buffer); // 执行DAP命令
    res &= 0xFFFF;                                                      // 确保结果在16位范围内

    usbip_network_send(kSock, el_process_buffer, res, 0);               // 发送处理结果
    // 发送处理结果
    //int ret=c
    //ESP_LOGE("MdLink", "len: %d, len: %d", res,ret);
}

/**
 * @brief 接收完整数据
 * @param fd 套接字描述符
 * @param buf 接收缓冲区
 * @param size 需要接收的数据大小
 * @param flag 接收标志
 * @return 成功返回接收的总字节数，失败返回错误码
 */
static inline int recv_all(int fd, uint8_t *buf, size_t size, int flag)
{
    const size_t total = size; // 记录总数据大小
    int ret;                   // 接收返回值

    if (size == 0) // 如果数据大小为0
        return 0;  // 直接返回

    // 循环接收直到收满指定大小的数据
    do
    {
        ret = recv(fd, buf, size, flag); // 接收数据
        if (ret <= 0)                    // 如果接收失败
            return ret;                  // 返回错误码

        buf += ret;  // 移动缓冲区指针
        size -= ret; // 更新剩余数据大小
    } while (size); // 循环直到数据收满

    return total; // 返回接收的总字节数
}

/**
 * @brief 供应商命令预处理
 * @param base 数据基地址
 * @param recved_len 已接收数据长度
 * @return 成功返回1，失败返回错误码
 */
static int el_vendor_command_pre_process(uint8_t *base, int recved_len)
{
    int offset = 0;                          // 数据偏移量
    int payload_len, remain_len, packet_len; // 定义长度变量
    uint16_t *payload;                       // 定义有效载荷指针
    int ret;                                 // 返回值

    // 处理完整的数据包
    while (recved_len - offset >= 4) // 当剩余数据足够处理时
    {
        payload = (uint16_t *)(base + offset + 2); // 跳过头部，指向有效载荷
        payload_len = ntohs(*payload);             // 获取有效载荷长度
        packet_len = 4 + payload_len;              // 计算数据包总长度（头部+有效载荷）

        if (offset + packet_len > recved_len) // 如果数据包不完整
            break;                            // 跳出循环

        el_dap_data_process(base + offset, packet_len); // 处理数据包
        offset += packet_len;                           // 更新偏移量
    }

    // 处理剩余数据
    remain_len = recved_len - offset; // 计算剩余数据长度
    if (remain_len == 0)              // 如果没有剩余数据
        return 1;                     // 返回成功

    // 移动剩余数据到缓冲区开头
    memmove(base, base + offset, remain_len); // 移动数据

    // 如果剩余数据不足4字节，继续接收
    if (remain_len < 4) // 如果剩余数据不足
    {
        ret = recv(kSock, base + remain_len, 4 - remain_len, 0); // 接收剩余数据
        if (ret <= 0)                                            // 如果接收失败
            return ret;                                          // 返回错误码
        offset = 4;                                              // 更新偏移量
        remain_len = 0;                                          // 剩余数据长度为0
    }
    else
    {
        offset = remain_len; // 更新偏移量
        remain_len -= 4;     // 扣除头部长度
    }

    // 接收剩余的有效载荷数据
    payload = (uint16_t *)(base + 2); // 指向有效载荷长度字段
    payload_len = ntohs(*payload);    // 获取有效载荷长度
    if (payload_len - remain_len > 0) // 如果还有数据未接收
    {
        ret = recv(kSock, base + offset, payload_len - remain_len, 0); // 接收剩余数据
        if (ret <= 0)                                                  // 如果接收失败
            return ret;                                                // 返回错误码
    }

    // 处理完整的数据包
    el_dap_data_process(base, 4 + payload_len); // 处理完整数据包

    return 1; // 返回成功
}
#include "esp_log.h"
/**
 * @brief DAP工作主函数
 * @param base 数据基地址
 * @param len 缓冲区长度
 * @return 成功返回0，失败返回错误码
 */
int el_dap_work(uint8_t *base, size_t len)
{
    uint16_t *length, payload_len; // 定义长度变量
    uint8_t *data;                 // 数据指针
    int sz, ret;                   // 定义变量
    int retry_count = 0;
    // 初始化上下文
    memset(&k_el_context, 0, sizeof(struct el_context)); // 清零上下文

    // 读取命令码和协议版本
    data = base + 4; // 跳过协议头
    sz = 8;          // 设置读取大小
    do
    {
        ret = recv(kSock, data, sz, 0); // 接收数据
        if (ret <= 0)                   // 如果接收失败
            return ret;                 // 返回错误码
        sz -= ret;                      // 更新剩余大小
        data += ret;                    // 移动数据指针
    } while (sz > 0); // 循环直到数据收满

    // 处理握手
    ret = el_handshake_process(kSock, base, 12); // 执行握手处理
    if (ret)                                     // 如果握手失败
        return ret;                              // 返回错误码

    // 设置重启标志并分配处理缓冲区
    kRestartDAPHandle = DELETE_HANDLE; // 设置重启标志
    el_process_buffer_malloc();        // 分配处理缓冲区
    //ESP_LOGI("MdLink", "DAP work start");
    // 主处理循环
    while (1)
    {
        // ret = recv(kSock, base, len, 0);
        // if (ret <= 0)
        //     return ret;
        // el_dap_data_process(base, ret);
        do {
            ret = recv(kSock, base, len, 0);
            if (ret > 0)
                break;

            if (ret == 0) {
                ESP_LOGE("MdLink", "Connection closed by peer");
            } else {
                ESP_LOGE("MdLink", "recv error: %d (errno: %d)", ret, errno);
            }
            if(++retry_count==3)
                return ret;                                 // 返回错误码

            vTaskDelay(pdMS_TO_TICKS(100 * retry_count));
        } while (1);
        //ESP_LOGI("MdLink", "command: %x", *base);
        //ESP_LOGI("MdLink", "recv len: %d", ret);
        // for(int i=0;i<ret;i++)
        // {
        //     ESP_LOGI("MdLink", "recv %d data: %x", i ,base[i]);
        // }
        // 根据数据类型进行处理
        if (*base == EL_VENDOR_COMMAND_PERFIX) // 如果是供应商命令
        {
            ret = el_vendor_command_pre_process(base, ret); // 预处理供应商命令
            if (ret <= 0)                                   // 如果处理失败
                return ret;                                 // 返回错误码
        }
        else
        {//普通DAP数据
            el_dap_data_process(base, ret); // 处理DAP数据
        }

        // 异步模式处理
        if (k_el_context.is_async) // 如果是异步模式
        {
            
            do
            {
                // 接收数据包头
                ret = recv_all(kSock, base, 4, 0); // 接收包头
                if (ret <= 0)                      // 如果接收失败
                    return ret;                    // 返回错误码
                length = (uint16_t *)(base + 2);   // 指向长度字段
                payload_len = ntohs(*length);      // 获取有效载荷长度

                // 接收数据包体
                ret = recv_all(kSock, base + 4, payload_len, 0); // 接收包体
                if (ret <= 0)                                    // 如果接收失败
                    return ret;                                  // 返回错误码
                el_dap_data_process(base, 4 + ntohs(*length));   // 处理数据包
            } while (k_el_context.is_async); // 循环直到退出异步模式
        }
    }

    return 0; // 返回成功
}

/**
 * @brief 原生命令透传处理
 * @param request 请求数据
 * @param response 响应缓冲区
 * @return 响应数据长度
 */
uint32_t el_native_command_passthrough(const uint8_t *request, uint8_t *response)
{
    int ret; // 定义返回值

    request += 2; // 获取命令类型
    // 执行DAP命令
    ret = DAP_ExecuteCommand(request, response + 3); // 执行DAP命令
    ret &= 0xFFFF;                                   // 确保结果在16位范围内

    // 填充响应头
    response[0] = 0x00;              // 设置状态
    response[1] = (ret >> 8) & 0xFF; // 设置长度高字节
    response[2] = ret & 0xFF;        // 设置长度低字节

    return ret + 4; // 返回总长度（头部+有效载荷）
}

/**
 * @brief 供应商命令处理
 * @param request 请求数据
 * @param response 响应缓冲区
 * @return 响应数据长度
 */
uint32_t el_vendor_command(const uint8_t *request, uint8_t *response)
{
    uint8_t type;     // 命令类型
    uint32_t ret = 0; // 返回值

    type = *request++; // 获取命令类型

    switch (type) // 根据命令类型处理
    {
    case EL_NATIVE_COMMAND_PASSTHROUGH:                         // 原生命令透传
        ret = el_native_command_passthrough(request, response); // 调用透传处理
        break;
    case EL_VENDOR_SCOPE_ENTER:                              // 进入异步模式
        memset(&k_el_context, 0, sizeof(struct el_context)); // 清零上下文
        k_el_context.is_async = true;                        // 设置为异步模式
        *response++ = 0;                                     // 设置状态
        *response++ = 0;
        *response++ = 0;
        ret = 4; // 返回长度
        break;
    case EL_VENDOR_SCOPE_EXIT:         // 退出异步模式
        k_el_context.is_async = false; // 设置为非异步模式
        *response++ = 0;               // 设置状态
        *response++ = 0;
        *response++ = 0;
        ret = 4; // 返回长度
        break;
    default:
        break;
    }

    return ret; // 返回处理结果长度
}